package logic;

import java.io.Serializable;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.Random;

public class Missions implements Serializable{

	private static final long serialVersionUID = 1L;
	private Set<Continent> chosenContinents = new HashSet<Continent>();
	private List<Continent> continents = new LinkedList<Continent>();
	private Set<Mission> missions = new HashSet<Mission>();
	private List<Player> players;

	public Missions(GameMap map, List<Player> players) {
		for(Continent con : map.getContinents().values()){
			this.continents.add(con);
		}
		this.players = players;
	}

	public Mission getMission(Player player) {
		Random rand = new Random();
		while(true){
			if(players.size() == 2){
				return new MissionEliminatePlayer(getOtherPlayer(player));
			} else {
				Continent missionContinent = getNotChosenContinent();
				if(missionContinent.isLittle()){
					Continent secondContinent = getNotChosenDifferent(missionContinent);
					if(player.isComputer()){
						Mission m = new MissionDoubleConquer(missionContinent, secondContinent);
						if(missions.contains(m)) continue;
						missions.add(m);
						return m;
					}
					if(rand.nextBoolean()){
						Mission m = new MissionDoubleConquer(missionContinent, secondContinent);
						if(missions.contains(m)) continue;
						missions.add(m);
						return m;
					} else {
						Mission m = new MissionDoubleConquer(missionContinent, secondContinent, 2);
						if(missions.contains(m)) continue;
						missions.add(m);
						return m;
					}
				} else {
					chosenContinents.add(missionContinent);
					if(rand.nextBoolean()){
						Mission m = new MissionConquerContinent(missionContinent);
						if(missions.contains(m)) continue;
						missions.add(m);
						return m;
					} else {
						Mission m = new MissionConquerContinent(missionContinent,2);
						if(missions.contains(m)) continue;
						missions.add(m);
						return m;
					}
				}
			}
		}
	}

	/**
	 * returns a player which is not the argument
	 * @param player
	 * @return
	 */
	private Player getOtherPlayer(Player player){
		for(Player p : this.players){
			if(!p.equals(player)) return p;
		}
		return null;
	}

	/**
	 * @return a continent which is not used yet
	 */
	private Continent getNotChosenContinent(){
		Random random = new Random();
		boolean againg = true;
		Continent continent = null;
		while(againg){
			continent = continents.get(Math.abs(random.nextInt()%continents.size()));
			againg = chosenContinents.contains(continent);
		}
		return continent;
	}
	
	/**
	 * @return a continent which is not chosen yet and which is different
	 * from the continent other
	 * @param other continent
	 */
	private Continent getNotChosenDifferent(Continent other){
		boolean again = true;
		Continent temp = null;
		while(again){
			temp = getNotChosenContinent();
			again = temp.equals(other) || !temp.isLittle();
		}
		return temp;
	}
}
